<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    .table {
      position: relative;
      margin: 100px auto;
      width: 1080px;
      height: 596px;
      background: url(../../image/破产.jpg) no-repeat;
      background-size: 100%;
    }

    .big {
      position: absolute;
      width: 1000px;
      height: 500px;
      left: 43px;
      top: 48px;
    }

    .box,
    .box2 {
      width: 50px;
      height: 50px;
      border-radius: 50%;
      box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.5);
      position: absolute;
    }

    .box {
      background: radial-gradient(circle at 75% 30%, #fff 5px, #fffbfef1 8%, #aaaaaac4 60%, #faf6f9bd 100%);
    }

    .box2 {
      background: radial-gradient(circle at 75% 30%, #fff 5px, #ff21f4f1 8%, #d61d1dc4 60%, #ff219b 100%);
    }

    .big .box::before,
    .box2::before {
      content: '';
      position: absolute;
      width: 100%;
      height: 100%;
      transform: scale(0.25) translate(-70%, -70%);
      background: radial-gradient(#fff, transparent);
      border-radius: 50%;
    }

    .gan {
      display: flex;
      height: 20px;
      position: absolute;
      left: 25px;
      top: 15px;
      transform-origin: 0 50%;
      transform: rotate(50deg);
      cursor: pointer;
    }

    .gan2 {
      width: 25px;
      height: 20px;
    }

    .gan3 {
      width: 375px;
      height: 20px;
      background: url(../../image/cun1.jpg) no-repeat center;
      background-size: 100%;
    }
    </style>
</head>
<body>

  
    <div class="table">
    <div class="big">
      <div class="box">
        <div class="gan">
          <div class="gan2"></div>
          <div class="gan3"></div>
        </div>
      </div>
      <div class="box2"></div>
    </div>
  </div>
  
 <script>
     //JS
   // 设置球的位置
    //母球
    const box1 = document.querySelector('.box')
    box1.style.left = '300px'
    box1.style.top = '150px'
    //子球
    const box2 = document.querySelector('.box2')
    box2.style.left = '700px'
    box2.style.top = '300px'
    //球杆
    const gan = document.querySelector('.gan')
    const gan2 = document.querySelector('.gan2')
    const gan3 = document.querySelector('.gan3')


      //声明鼠标相对坐标变量
      let x, y
    // 获取鼠标的坐标,来计算球杆的角度
    document.addEventListener('mousemove', function (e) {
      const position = box1.getBoundingClientRect()
      // 获取鼠标相对球心的坐标，因为盒子的position原点在左上角，所以要减去自身宽高的一半才是球心
      x = e.pageX - position.left - 25
      y = e.pageY - position.top - 25 - document.documentElement.scrollTop
      let z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); // 勾股定理计算斜边值
      let cos = y / z;// 余弦
      let radian = Math.acos(cos);//用反三角函数求弧度
      let angle = 180 / (Math.PI / radian);//将弧度转换成角度
      if (x > 0 && y > 0) {//鼠标在第四象限
        angle = 90 - angle
      }
      if (x == 0 && y > 0) {//鼠标在y轴负方向上
        angle = 90;
      }
      if (x == 0 && y < 0) {//鼠标在y轴正方向上
        angle = 270;
      }
      if (x > 0 && y == 0) {//鼠标在x轴正方向上
        angle = 0;
      }
      if (x < 0 && y > 0) {//鼠标在第三象限
        angle = 90 + angle
      }
      if (x < 0 && y == 0) {//鼠标在x轴负方向
        angle = 180;
      }
      if (x < 0 && y < 0) {//鼠标在第二象限
        angle = 90 + angle
      }
      if (x > 0 && y < 0) {//鼠标在第一象限
        angle = 450 - angle
      }
      // 把计算出来的角度取模后赋值给球杆旋转角度
      gan.style.transform = `rotate(${angle % 360}deg)`
    })


   // // 球杆点击事件
   document.querySelector('.gan3').addEventListener('click', function () {
      moveGan(gan2, 0)
    })
    // 球杆打击动画
    function moveGan(item, num) {
      // i来控制函数的结束条件
      let i = num
      requestAnimationFrame(() => {
        //获取元素的坐标值,要把字符串里的数字提取出来
        let moveX = parseFloat(item.style.width) || 25
        moveX += 15
        // 每一次调用这个函数，就让元素的宽+15px
        item.style.width = moveX + 'px'
        i++
        if (i >= 10) {
          // i>10时，就让球杆再缩回去
          return returnGan(item, 0)
        }
        // 使用尾递归来重复调用
        return moveGan(item, i)
      })
    }
    function returnGan(item, num) {
      let i = num
      requestAnimationFrame(() => {
        let moveX = parseFloat(item.style.width) || 0
        moveX -= 15
        // 每一次调用这个函数，就让元素的宽-15px
        item.style.width = moveX + 'px'
        i++
        if (i >= 10) {
          return tick() //tick是击球的函数
        }
        return returnGan(item, i)
      })
    }

    // 击打母球的函数
    function tick() {
      // 通过绝对值判断打击角度，x和y就是鼠标相对球心的坐标
      if (Math.abs(x) > Math.abs(y)) {
        // 通过判断x,y是否大于0,判断打击方向
        if (x > 0 && y > 0 || x > 0 && y < 0) {
          raf(box1, -1, -1 / (x / y), 1000)
        } else {
          raf(box1, 1, 1 / (x / y), 1000)
        }
      } else {
        if (y > 0 && x > 0 || y > 0 && x < 0) {
          raf(box1, -1 / (y / x), -1, 1000)
        } else {
          raf(box1, 1 / (y / x), 1, 1000)
        }
      }
    }
    
   //..... 母球移动的函数里面还要加代码，所以这里就先不贴出来了。 
   
   // 判断是否进洞的函数
    function test(x, y) {
      if (x < 10 && y < 10 || x > 940 && y < 10 || x > 940 && y > 440 || x < 10 && y > 440
        || x > 475 && x < 525 && y < 5 || x > 475 && x < 525 && y > 445) {
        return true
      }
    }

     //母球移动
    // 获取坐标,要把字符串里的数字提取出来
    let fx = parseFloat(box1.style.left)
    let fy = parseFloat(box1.style.top)
    let gx = parseFloat(box2.style.left)
    let gy = parseFloat(box2.style.top)
    // 声明用判断撞球角度的变量
    let n
    // 控制子球移动函数的调用
    let p = true
    function raf(item, x, y, num) {
      //击球后隐藏球杆
      gan3.style.display = 'none'
      // item是目标元素,x和y对应移动方向的系数,i用来控制移动速度
      let i = num
      requestAnimationFrame(() => {
        fx += x * 5 * i / 500
        fy += y * 5 * i / 500
        item.style.left = fx + 'px'
        item.style.top = fy + 'px'
        i -= 2
        // 边界判断，球桌宽1000高500，球宽高50，所以边界就是0-950
        if (fx > 950) { // 右边界，让x系数反过来
          fx = 950
          return raf(item, -x, y, i)
        } else if (fy > 450) { // 下边界，让y系数反过来
          fy = 450
          return raf(item, x, -y, i)
        } else if (fx < 0) { // 左边界，让x系数反过来
          fx = 0
          return raf(item, -x, y, i)
        } else if (fy < 0) { // 上边界，让y系数反过来
          fy = 0
          return raf(item, x, -y, i)
        }
        // i<=50就停止移动，然后显示球杆
        if (i <= 50) return gan3.style.display = 'block'
        // 判断球是否进洞
        if (test(fx, fy)) {
          return item.style.display = 'none'
        }
        //两个球撞击时的判断
        if (fx < gx + 50 && fx > gx - 50 && fy < gy + 50 && fy > gy - 50) {
          // 子球前进的角度,就是撞击时,两个圆心连线的夹角
          n = Math.abs(gx - fx) >= Math.abs(gy - fy) ? Math.abs(gx - fx) : Math.abs(gy - fy)
          // n用来控制调用函数时x,y的大小,不能大于1,否则移动速度会异常
          if (p) raf2(box2, (gx - fx) / n, (gy - fy) / n, i)
          // 只有第一次碰撞时,会调用一次子球移动的函数,避免一次击球产生多次撞击时,这个函数被多次调用
          p = false
          return raf(item, -x, y, i)
        }
        return raf(item, x, y, i)
      })
    }
     //子球移动
    function raf2(item, x, y, num) {
      let i = num
      requestAnimationFrame(() => {
        //获取元素的坐标值,要把字符串里的数字提取出来
        gx += x * 5 * i / 700
        gy += y * 5 * i / 700
        item.style.left = gx + 'px'
        item.style.top = gy + 'px'
        i -= 2
        if (gx > 950) {
          gx = 950
          return raf2(item, -x, y, i)
        } else if (gy > 450) {
          gy = 450
          return raf2(item, x, -y, i)
        } else if (gx < 0) {
          gx = 0
          return raf2(item, -x, y, i)
        } else if (gy < 0) {
          gy = 0
          return raf2(item, x, -y, i)
        }
        //两个球触碰判断
        if (fx < gx + 50 && fx > gx - 50 && fy < gy + 50 && fy > gy - 50) {
          return raf2(box2, (gx - fx) / n, (gy - fy) / n, i)
        }
        if (i <= 50) return p = true // 移动函数执行完后，重置p这个变量
        // 判断球是否进洞
        if (test(gx, gy)) {
          return item.style.display = 'none'
        }
        return raf2(item, x, y, i)
      })
    }

 </script>
    
</body>
</html>